<template>
  <div id="v-tags-view" class="v-tags-view flex w-full relative h-[var(--tags-view-height)] bg-[var(--el-bg-color)] border-bottom">
    <span
      class="v-tags-view__tool v-tags-view__tool--first w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex-center cursor-pointer"
      @click="move(-200)"
    >
      <EcoIcon icon="el-icon-DArrowLeft" color="var(--el-text-color-placeholder)" />
    </span>
    <div class="overflow-hidden flex-1 h-[var(--tags-view-height)]">
      <el-scrollbar ref="scrollbarRef" @scroll="scroll">
        <div class="flex h-[var(--tags-view-height)]">
          <Dropdown
            :ref="itemRefs.set"
            :item-attrs="getItemAttrs(tag)"
            v-for="tag in visitedViews"
            :key="tag.fullPath"
            :tag-item="tag"
            :class="[
              'v-tags-view__item',
              tag?.affix ? 'v-tags-view__item--affix p-r[15px]' : 'p-r[25px]',
              {
                'is-active': isActive(tag)
              }
            ]"
            @visible-change="visibleChange"
          >
            <div>
              <router-link :ref="tagRefs.set" :to="{ ...tag }" custom v-slot="{ navigate }">
                <div @click="navigate" class="h-full flex justify-center items-center whitespace-nowrap pl-15px">
                  <EcoIcon v-if="tagsViewIcon && tag.icon" :icon="tag.icon" size="12px" class="mr-5px" />
                  {{ tag.title }}
                  <EcoIcon
                    v-if="!tag?.affix"
                    class="v-tags-view__item--close"
                    icon="el-icon-Close"
                    size="12px"
                    @click.prevent.stop="closeSelectedTag(tag)"
                  />
                </div>
              </router-link>
            </div>
          </Dropdown>
        </div>
      </el-scrollbar>
    </div>
    <span class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex-center cursor-pointer" @click="move(200)">
      <EcoIcon icon="el-icon-DArrowRight" color="var(--el-text-color-placeholder)" />
    </span>
    <span
      class="v-tags-view__tool w-[var(--tags-view-height)] h-[var(--tags-view-height)] flex-center cursor-pointer"
      @click="refreshSelectedTag(selectedTag)"
    >
      <EcoIcon icon="el-icon-Refresh" color="var(--el-text-color-placeholder)" />
    </span>
  </div>
</template>
<script setup lang="ts">
import { useTagsViewStore, useAuthStore, useSettingStore } from '@/stores'
import { TagView } from '@/stores/interface'
import { RouterLinkProps } from 'vue-router'
import { filterAffixTags } from '@/utils/router'
import { ElDropdown, ElScrollbar } from 'element-plus'
import { useScrollTo, useTagsView } from '@/hooks'
import Dropdown from '@/components/Dropdown/index.vue'
const { push, currentRoute } = useRouter()
const route = useRoute()

const { closeAll, closeLeft, closeRight, closeOther, closeCurrent, refreshPage } = useTagsView()

// elscroll 实例
const scrollbarRef = ref<InstanceType<typeof ElScrollbar>>()
const tagsViewStore = useTagsViewStore()
const authStore = useAuthStore()
const settingStore = useSettingStore()
const { tagsViewIcon } = storeToRefs(settingStore)
const tagRefs = useTemplateRefsList<RouterLinkProps>()
const tagRouterRefs = useTemplateRefsList<RouterLinkProps>()
// 所有右键菜单组件的元素
const itemRefs = useTemplateRefsList<
  InstanceType<
    typeof Dropdown & {
      elDropdownMenuRef: InstanceType<typeof ElDropdown>
      tagItem: TagView
    }
  >
>()
const visitedViews = computed(() => tagsViewStore.getVisitedViews)

const affixTags = ref<TagView[]>([])
const selectedTag = computed(() => tagsViewStore.getSelectedTag as TagView)
const setSelectTag = tagsViewStore.setSelectedTag
const routers = computed(() => authStore.getAuthRoutes)
const getItemAttrs = (item: TagView) => [
  {
    icon: 'el-icon-Refresh',
    label: '重新加载',
    disabled: unref(selectedTag).fullPath !== item.fullPath,
    command: () => {
      refreshSelectedTag(item)
    }
  },

  {
    icon: 'el-icon-Close',
    label: '关闭标签',
    disabled: !!unref(visitedViews)?.length && unref(selectedTag)?.affix,
    command: () => {
      closeSelectedTag(item)
    }
  },
  {
    icon: 'el-icon-ArrowLeft',
    label: '关闭左侧',
    disabled: !!unref(visitedViews)?.length && (item.fullPath === unref(visitedViews)[0].fullPath || unref(selectedTag)?.fullPath !== item.fullPath),
    command: () => {
      closeLeftTags()
    }
  },
  {
    icon: 'el-icon-ArrowRight',
    label: '关闭右侧',
    disabled:
      !!unref(visitedViews)?.length &&
      (item.fullPath === unref(visitedViews)[unref(visitedViews).length - 1].fullPath || unref(selectedTag)?.fullPath !== item.fullPath),
    command: () => {
      closeRightTags()
    }
  },
  {
    icon: 'el-icon-Checked',
    label: '关闭其他',
    disabled: unref(selectedTag)?.fullPath !== item.fullPath,
    command: () => {
      closeOthersTags()
    }
  },
  {
    icon: 'el-icon-Minus',
    label: '关闭全部',
    command: () => {
      closeAllTags()
    }
  }
]

// 去最后一个
const toLastView = () => {
  const visitedViews = tagsViewStore.getVisitedViews
  const latestView = visitedViews.slice(-1)[0]
  if (latestView) {
    push(latestView)
  } else {
    if (unref(currentRoute).path === authStore.getAuthRoutes[0].path || unref(currentRoute).path === authStore.getAuthRoutes[0].redirect) {
      addTags()
      return
    }
    push(authStore.getAuthRoutes[0].path)
  }
}

// 右键菜单状态改变的时候
const visibleChange = (visible: boolean, tagItem: TagView) => {
  if (visible) {
    for (const v of unref(itemRefs)) {
      const elDropdownMenuRef = v.elDropdownMenuRef
      if (tagItem.fullPath !== v.tagItem.fullPath) {
        elDropdownMenuRef?.handleClose()
        setSelectTag(tagItem)
      }
    }
  }
}

// 是否是当前tag
const isActive = (tag: TagView): boolean => {
  return tag.path === route.path
}

const closeAllTags = () => {
  closeAll(() => {
    toLastView()
  })
}
// 关闭其它
const closeOthersTags = () => {
  closeOther()
}
// 重新加载
const refreshSelectedTag = async (view: TagView) => {
  refreshPage(view)
}

// 关闭左侧
const closeLeftTags = () => {
  closeLeft()
}

// 关闭右侧
const closeRightTags = () => {
  closeRight()
}
// 关闭选中的tag
const closeSelectedTag = (view: TagView) => {
  closeCurrent(view, () => {
    if (isActive(view)) {
      toLastView()
    }
  })
}

// 新增tag
const addTags = () => {
  const title = route.meta.title
  if (title) {
    const Tag: TagView = {
      name: route.name as string,
      title: route.meta.title as string,
      icon: route.meta.icon as string,
      path: route.path,
      fullPath: route.fullPath,
      affix: route.meta?.affix as boolean,
      keepAlive: route.meta?.keepAlive as boolean,
      query: route.query
    }
    setSelectTag(Tag)
    tagsViewStore.addView(Tag)
  }
}

// 保存滚动位置
const scrollLeftNumber = ref(0)

const scroll = (val: { scrollLeft: number }) => {
  scrollLeftNumber.value = val.scrollLeft as number
}

// 移动到某个位置
const move = (to: number) => {
  const wrap$ = unref(scrollbarRef)?.wrapRef
  const { start } = useScrollTo({
    el: wrap$!,
    position: 'scrollLeft',
    to: unref(scrollLeftNumber) + to,
    duration: 500
  })
  start()
}

// 滚动到选中的tag
const moveToCurrentTag = async () => {
  await nextTick()
  for (const v of unref(visitedViews)) {
    if (v.fullPath === route.path) {
      moveToTarget(v)
      if (v.fullPath !== route.fullPath) {
        tagsViewStore.updateVisitedView({
          name: route.name as string,
          title: (route.meta.title as string) || '',
          path: route.path,
          icon: route.meta.icon as string,
          fullPath: route.fullPath,
          affix: route.meta?.affix as boolean,
          keepAlive: route.meta?.keepAlive as boolean,
          query: route.query
        })
      }

      break
    }
  }
}

const moveToTarget = (currentTag: TagView) => {
  const wrap$ = unref(scrollbarRef)?.wrapRef
  let firstTag: Nullable<RouterLinkProps> = null
  let lastTag: Nullable<RouterLinkProps> = null
  const tagList = unref(tagRouterRefs)
  // find first tag and last tag
  if (tagList.length > 0) {
    firstTag = tagList[0]
    lastTag = tagList[tagList.length - 1]
  }
  if ((firstTag?.to as TagView).fullPath === currentTag.fullPath) {
    // 直接滚动到0的位置
    const { start } = useScrollTo({
      el: wrap$!,
      position: 'scrollLeft',
      to: 0,
      duration: 500
    })
    start()
  } else if ((lastTag?.to as TagView).fullPath === currentTag.fullPath) {
    // 滚动到最后的位置
    const { start } = useScrollTo({
      el: wrap$!,
      position: 'scrollLeft',
      to: wrap$!.scrollWidth - wrap$!.offsetWidth,
      duration: 500
    })
    start()
  } else {
    // find preTag and nextTag
    const currentIndex: number = tagList.findIndex(item => (item?.to as TagView).fullPath === currentTag.fullPath)
    const tgsRefs = document.getElementsByClassName('v-tags-view__item')

    const prevTag = tgsRefs[currentIndex - 1] as HTMLElement
    const nextTag = tgsRefs[currentIndex + 1] as HTMLElement

    // the tag's offsetLeft after of nextTag
    const afterNextTagOffsetLeft = nextTag.offsetLeft + nextTag.offsetWidth + 4

    // the tag's offsetLeft before of prevTag
    const beforePrevTagOffsetLeft = prevTag.offsetLeft - 4

    if (afterNextTagOffsetLeft > unref(scrollLeftNumber) + wrap$!.offsetWidth) {
      const { start } = useScrollTo({
        el: wrap$!,
        position: 'scrollLeft',
        to: afterNextTagOffsetLeft - wrap$!.offsetWidth,
        duration: 500
      })
      start()
    } else if (beforePrevTagOffsetLeft < unref(scrollLeftNumber)) {
      const { start } = useScrollTo({
        el: wrap$!,
        position: 'scrollLeft',
        to: beforePrevTagOffsetLeft,
        duration: 500
      })
      start()
    }
  }
}

const initTags = () => {
  const tags: TagView[] = filterAffixTags(unref(routers))
  affixTags.value = tags
  for (const tag of unref(tags)) {
    if (tag.name) {
      tagsViewStore.addVisitedView(tag)
    }
  }
}
onMounted(() => {
  initTags()
  addTags()
})
watch(
  () => route.name,
  () => {
    addTags()
    moveToCurrentTag()
  }
)
watch(
  visitedViews,
  () => {
    // 清空tagRouterRefs
    unref(tagRouterRefs).splice(0, unref(tagRouterRefs).length)
    unref(visitedViews).forEach(vi => {
      unref(tagRouterRefs).push(unref(tagRefs).find(tag => (tag?.to as TagView).fullPath === vi.fullPath) as RouterLinkProps)
    })
  },
  {
    deep: true,
    flush: 'post'
  }
)
</script>
<style lang="scss" scoped>
.v-tags-view {
  :deep(el-scrollbar__view) {
    height: 100%;
  }
  &__tool {
    position: relative;
    &::before {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: calc(100% - 1px);
      content: '';
      border-left: 1px solid var(--el-border-color);
    }
    &--first {
      &::before {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: calc(100% - 1px);
        content: '';
        border-right: 1px solid var(--el-border-color);
        border-left: none;
      }
    }
  }
  &__item {
    position: relative;
    top: 2px;
    height: calc(100% - 6px);
    margin-left: 4px;
    font-size: 12px;
    cursor: pointer;
    border: 1px solid #d9d9d9;
    border-radius: 2px;
    &--close {
      position: absolute;
      top: 50%;
      right: 5px;
      display: none;
      transform: translate(0, -50%);
    }
    &:not(.v-tags-view__item--affix):hover {
      .v-tags-view__item--close {
        display: block;
      }
    }
  }
  &__item:not(.is-active) {
    &:hover {
      color: var(--el-color-primary);
    }
  }
  &__item.is-active {
    color: var(--el-color-white);
    background-color: var(--el-color-primary);
    border: 1px solid var(--el-color-primary);
    .v-tags-view__item--close {
      :deep(svg) {
        color: var(--el-color-white) !important;
      }
    }
  }
}
.dark {
  .v-tags-view {
    &__tool {
      &--first {
        &::after {
          display: none;
        }
      }
    }
    &__item {
      border: 1px solid var(--el-border-color);
    }
    &__item:not(.is-active) {
      &:hover {
        color: var(--el-color-primary);
      }
    }
    &__item.is-active {
      color: var(--el-color-white);
      background-color: var(--el-color-primary);
      border: 1px solid var(--el-color-primary);
      .v-tags-view__item--close {
        :deep(svg) {
          color: var(--el-color-white) !important;
        }
      }
    }
  }
}
</style>
